Android 4.4 WiFi代理流程
看雪论坛作者ID:卓桐
packages/apps/Settings/src/com/android/settings/wifi/WifiConfigController.java
public WifiConfigController(
WifiConfigUiBase parent, View view, AccessPoint accessPoint, boolean edit) {
...
WifiInfo info = mAccessPoint.getInfo();
if (info != null && info.getLinkSpeed() != -1) {
addRow(group, R.string.wifi_speed, info.getLinkSpeed() + WifiInfo.LINK_SPEED_UNITS);
}
addRow(group, R.string.wifi_security, mAccessPoint.getSecurityString(false));
boolean showAdvancedFields = false;
if (mAccessPoint.networkId != INVALID_NETWORK_ID) {
WifiConfiguration config = mAccessPoint.getConfig();
if (config.ipAssignment == IpAssignment.STATIC) {
mIpSettingsSpinner.setSelection(STATIC_IP);
showAdvancedFields = true;
} else {
mIpSettingsSpinner.setSelection(DHCP);
}
//Display IP addresses
for(InetAddress a : config.linkProperties.getAddresses()) {
addRow(group, R.string.wifi_ip_address, a.getHostAddress());
}
//构造函数,从设置中取出状态,是否设置代理
if (config.proxySettings == ProxySettings.STATIC) {
mProxySettingsSpinner.setSelection(PROXY_STATIC);
showAdvancedFields = true;
} else if (config.proxySettings == ProxySettings.PAC) {
mProxySettingsSpinner.setVisibility(View.GONE);
TextView textView = (TextView)mView.findViewById(R.id.proxy_pac_info);
textView.setVisibility(View.VISIBLE);
textView.setText(context.getString(R.string.proxy_url) +
config.linkProperties.getHttpProxy().getPacFileUrl());
showAdvancedFields = true;
} else {
mProxySettingsSpinner.setSelection(PROXY_NONE);
}
}
...
//展示代理信息
private void showProxyFields() {
WifiConfiguration config = null;
mView.findViewById(R.id.proxy_settings_fields).setVisibility(View.VISIBLE);
if (mAccessPoint != null && mAccessPoint.networkId != INVALID_NETWORK_ID) {
config = mAccessPoint.getConfig();
}
if (mProxySettingsSpinner.getSelectedItemPosition() == PROXY_STATIC) {
mView.findViewById(R.id.proxy_warning_limited_support).setVisibility(View.VISIBLE);
mView.findViewById(R.id.proxy_fields).setVisibility(View.VISIBLE);
if (mProxyHostView == null) {
mProxyHostView = (TextView) mView.findViewById(R.id.proxy_hostname);
mProxyHostView.addTextChangedListener(this);
mProxyPortView = (TextView) mView.findViewById(R.id.proxy_port);
mProxyPortView.addTextChangedListener(this);
mProxyExclusionListView = (TextView) mView.findViewById(R.id.proxy_exclusionlist);
mProxyExclusionListView.addTextChangedListener(this);
}
if (config != null) {
//获取设置过的代理信息
ProxyProperties proxyProperties = config.linkProperties.getHttpProxy();
if (proxyProperties != null) {
mProxyHostView.setText(proxyProperties.getHost());
mProxyPortView.setText(Integer.toString(proxyProperties.getPort()));
mProxyExclusionListView.setText(proxyProperties.getExclusionList());
}
}
} else {
mView.findViewById(R.id.proxy_warning_limited_support).setVisibility(View.GONE);
mView.findViewById(R.id.proxy_fields).setVisibility(View.GONE);
}
}
//保存代理设置
private boolean ipAndProxyFieldsAreValid() {
mLinkProperties.clear();
mIpAssignment = (mIpSettingsSpinner != null &&
mIpSettingsSpinner.getSelectedItemPosition() == STATIC_IP) ?
IpAssignment.STATIC : IpAssignment.DHCP;
if (mIpAssignment == IpAssignment.STATIC) {
int result = validateIpConfigFields(mLinkProperties);
if (result != 0) {
return false;
}
}
mProxySettings = (mProxySettingsSpinner != null &&
mProxySettingsSpinner.getSelectedItemPosition() == PROXY_STATIC) ?
ProxySettings.STATIC : ProxySettings.NONE;
if (mProxySettings == ProxySettings.STATIC && mProxyHostView != null) {
String host = mProxyHostView.getText().toString();
String portStr = mProxyPortView.getText().toString();
String exclusionList = mProxyExclusionListView.getText().toString();
int port = 0;
int result = 0;
try {
port = Integer.parseInt(portStr);
//验证host和port是否正确
result = ProxySelector.validate(host, portStr, exclusionList);
} catch (NumberFormatException e) {
result = R.string.proxy_error_invalid_port;
}
if (result == 0) {
ProxyProperties proxyProperties= new ProxyProperties(host, port, exclusionList);
mLinkProperties.setHttpProxy(proxyProperties);
} else {
return false;
}
}
return true;
}
public void setHttpProxy(ProxyProperties proxy) {
mHttpProxy = proxy;
}
public ProxyProperties getHttpProxy() {
return mHttpProxy;
}
//当添加新的网络或者编辑保存触发,远程调用mWifiManager.save
/* package */ void submit(WifiConfigController configController) {
final WifiConfiguration config = configController.getConfig();
if (config == null) {
if (mSelectedAccessPoint != null
&& mSelectedAccessPoint.networkId != INVALID_NETWORK_ID) {
mWifiManager.connect(mSelectedAccessPoint.networkId,
mConnectListener);
}
} else if (config.networkId != INVALID_NETWORK_ID) {
if (mSelectedAccessPoint != null) {
mWifiManager.save(config, mSaveListener);
}
} else {
if (configController.isEdit()) {
mWifiManager.save(config, mSaveListener);
} else {
mWifiManager.connect(config, mConnectListener);
}
}
if (mWifiManager.isWifiEnabled()) {
mScanner.resume();
}
updateAccessPoints();
}
1、不用定义aidl文件。
2、Messenger只提供了一个方法进行进程间通信,send(Message msg)方法,发送一个Message,没有返回值,要拿到返回值,需要把client的Messenger作为msg.replyTo参数传递过去,service端处理完之后,在调用客户端的Messenger的send(Message msg)方法把返回值传递回client,这个过程是异步的。而AIDL你可以自己指定方法,指定返回值,它获取返回值是同步的。而AIDL调用默认是同步的,当然其实也可以异步。以上是针对客户端来说。
3、使用AIDL的时候,service端每收到一个client端的请求时,就会启动一个线程(非主线程)去执行相应的操作。而Messenger,service端收到的请求是放在Handler的MessageQueue里面,Handler大家都用过,它需要绑定一个Thread,然后不断poll message执行相关操作,这个过程是同步执行的。
4、Messenger需要和Handler绑定使用。
这里简单说下,有兴趣的可以自己写写例子熟悉使用。
public void save(WifiConfiguration config, ActionListener listener) {
if (config == null) throw new IllegalArgumentException("config cannot be null");
validateChannel();
sAsyncChannel.sendMessage(SAVE_NETWORK, 0, putListener(listener), config);
}
case WifiManager.CONNECT_NETWORK:
case WifiManager.SAVE_NETWORK: {
WifiConfiguration config = (WifiConfiguration) msg.obj;
int networkId = msg.arg1;
if (config != null && config.isValid()) {
// This is restricted because there is no UI for the user to
// monitor/control PAC.
if (config.proxySettings != ProxySettings.PAC) {
if (DBG) Slog.d(TAG, "Connect with config" + config);
//继续传递msg
mWifiStateMachine.sendMessage(Message.obtain(msg));
} else {
Slog.e(TAG, "ClientHandler.handleMessage cannot process msg with PAC");
if (msg.what == WifiManager.CONNECT_NETWORK) {
replyFailed(msg, WifiManager.CONNECT_NETWORK_FAILED);
} else {
replyFailed(msg, WifiManager.SAVE_NETWORK_FAILED);
}
}
} else if (config == null
&& networkId != WifiConfiguration.INVALID_NETWORK_ID) {
if (DBG) Slog.d(TAG, "Connect with networkId" + networkId);
mWifiStateMachine.sendMessage(Message.obtain(msg));
} else {
Slog.e(TAG, "ClientHandler.handleMessage ignoring invalid msg=" + msg);
if (msg.what == WifiManager.CONNECT_NETWORK) {
replyFailed(msg, WifiManager.CONNECT_NETWORK_FAILED);
} else {
replyFailed(msg, WifiManager.SAVE_NETWORK_FAILED);
}
}
break;
}
case WifiManager.SAVE_NETWORK:
config = (WifiConfiguration) message.obj;
NetworkUpdateResult result = mWifiConfigStore.saveNetwork(config);
if (result.getNetworkId() != WifiConfiguration.INVALID_NETWORK_ID) {
replyToMessage(message, WifiManager.SAVE_NETWORK_SUCCEEDED);
} else {
loge("Failed to save network");
replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED,
WifiManager.ERROR);
}
break;
NetworkUpdateResult saveNetwork(WifiConfiguration config) {
if (VDBG) localLog("saveNetwork", config.networkId);
// A new network cannot have null SSID
if (config == null || (config.networkId == INVALID_NETWORK_ID &&
config.SSID == null)) {
return new NetworkUpdateResult(INVALID_NETWORK_ID);
}
boolean newNetwork = (config.networkId == INVALID_NETWORK_ID);
//新增或者更新
NetworkUpdateResult result = addOrUpdateNetworkNative(config);
int netId = result.getNetworkId();
/* enable a new network */
if (newNetwork && netId != INVALID_NETWORK_ID) {
//新增wifi,断开的当前连接的wifi,再连接指定wifi
mWifiNative.enableNetwork(netId, false);
mConfiguredNetworks.get(netId).status = Status.ENABLED;
}
//mWifiNative的调用会到wpa_ctrl,很复杂,就不列出了
mWifiNative.saveConfig();
sendConfiguredNetworksChangedBroadcast(config, result.isNewNetwork() ?
WifiManager.CHANGE_REASON_ADDED : WifiManager.CHANGE_REASON_CONFIG_CHANGE);
return result;
}
//主要是保存ip、代理
private NetworkUpdateResult addOrUpdateNetworkNative(WifiConfiguration config) {
...
//获取当前连接
WifiConfiguration currentConfig = mConfiguredNetworks.get(netId);
if (currentConfig == null) {
currentConfig = new WifiConfiguration();
currentConfig.ipAssignment = IpAssignment.DHCP;
currentConfig.proxySettings = ProxySettings.NONE;
currentConfig.networkId = netId;
}
readNetworkVariables(currentConfig);
mConfiguredNetworks.put(netId, currentConfig);
mNetworkIds.put(configKey(currentConfig), netId);
//把远程传进来的ip、代理等写入当前进程的WifiConfiguration
NetworkUpdateResult result = writeIpAndProxyConfigurationsOnChange(currentConfig, config);
result.setIsNewNetwork(newNetwork);
result.setNetworkId(netId);
return result;
}
WifiManager.LINK_CONFIGURATION_CHANGED_ACTION和WifiManager.NETWORK_STATE_CHANGED_ACTION
private class WifiStateReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
...
Message msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED,
new NetworkInfo(mNetworkInfo));
msg.sendToTarget();
} else if (intent.getAction().equals(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION)) {
mLinkProperties = intent.getParcelableExtra(WifiManager.EXTRA_LINK_PROPERTIES);
Message msg = mCsHandler.obtainMessage(EVENT_CONFIGURATION_CHANGED, mNetworkInfo);
msg.sendToTarget();
}
}
}
frameworks/base/services/java/com/android/server/ConnectivityService.java内
private static class DefaultNetworkFactory implements NetworkFactory {
...
public NetworkStateTracker createTracker(int targetNetworkType, NetworkConfig config) {
switch (config.radio) {
case TYPE_WIFI:
return new WifiStateTracker(targetNetworkType, config.name);
...
}
}
}
//构造函数内
try {
tracker = netFactory.createTracker(targetNetworkType, config);
mNetTrackers[targetNetworkType] = tracker;
} catch (IllegalArgumentException e) {
Slog.e(TAG, "Problem creating " + getNetworkTypeName(targetNetworkType)
+ " tracker: " + e);
continue;
}
tracker.startMonitoring(context, mTrackerHandler);
private class NetworkStateTrackerHandler extends Handler {
public NetworkStateTrackerHandler(Looper looper) {
super(looper);
}
public void handleMessage(Message msg) {
NetworkInfo info;
switch (msg.what) {
case NetworkStateTracker.EVENT_STATE_CHANGED: {
info = (NetworkInfo) msg.obj;
NetworkInfo.State state = info.getState();
...
} else if (state == NetworkInfo.State.CONNECTED) {
//调用handleConnectivityChange
handleConnect(info);
}
if (mLockdownTracker != null) {
mLockdownTracker.onNetworkInfoChanged(info);
}
break;
}
case NetworkStateTracker.EVENT_CONFIGURATION_CHANGED: {
info = (NetworkInfo) msg.obj;
handleConnectivityChange(info.getType(), false);
break;
}
...
}
}
}
}
//EVENT_CONFIGURATION_CHANGED和EVENT_STATE_CHANGED最后都会调用到
private void handleConnectivityChange(int netType, boolean doReset) {
...
if (mNetConfigs[netType].isDefault()) {
handleApplyDefaultProxy(newLp.getHttpProxy());
}
...
}
//所以应该全局代理的优先级比wifi代理高
private void handleApplyDefaultProxy(ProxyProperties proxy) {
...
if (mGlobalProxy != null) return;
if (!mDefaultProxyDisabled) {
sendProxyBroadcast(proxy);
}
}
}
//从这里和后面的全局代理有重叠,就不继续了
private void sendProxyBroadcast(ProxyProperties proxy) {
if (proxy == null) proxy = new ProxyProperties("", 0, "");
if (mPacManager.setCurrentProxyScriptUrl(proxy)) return;
if (DBG) log("sending Proxy Broadcast for " + proxy);
Intent intent = new Intent(Proxy.PROXY_CHANGE_ACTION);
intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING |
Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
intent.putExtra(Proxy.EXTRA_PROXY_INFO, proxy);
final long ident = Binder.clearCallingIdentity();
try {
mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
通过设置Settings.Global.GLOBAL_HTTP_PROXY_HOST/Settings.Global.HTTP_PROXY代理
//注册监听器
mSettingsObserver = new SettingsObserver(mHandler, EVENT_APPLY_GLOBAL_HTTP_PROXY);
mSettingsObserver.observe(mContext);
//实现
private static class SettingsObserver extends ContentObserver {
private int mWhat;
private Handler mHandler;
SettingsObserver(Handler handler, int what) {
super(handler);
mHandler = handler;
mWhat = what;
}
void observe(Context context) {
ContentResolver resolver = context.getContentResolver();
resolver.registerContentObserver(Settings.Global.getUriFor(
Settings.Global.HTTP_PROXY), false, this);
}
//当修改Settings.Global.HTTP_PROXY时触发
public void onChange(boolean selfChange) {
mHandler.obtainMessage(mWhat).sendToTarget();
}
}
//内部handler的部分代码
case EVENT_APPLY_GLOBAL_HTTP_PROXY: {
handleDeprecatedGlobalHttpProxy();
break;
}
//取出设置的http代理,封装
private void handleDeprecatedGlobalHttpProxy() {
String proxy = Settings.Global.getString(mContext.getContentResolver(),
Settings.Global.HTTP_PROXY);
if (!TextUtils.isEmpty(proxy)) {
String data[] = proxy.split(":");
if (data.length == 0) {
return;
}
String proxyHost = data[0];
int proxyPort = 8080;
if (data.length > 1) {
try {
proxyPort = Integer.parseInt(data[1]);
} catch (NumberFormatException e) {
return;
}
}
ProxyProperties p = new ProxyProperties(data[0], proxyPort, "");
setGlobalProxy(p);
}
}
//解析出host和port,用Settings.Global.GLOBAL_HTTP_PROXY_HOST存储
public void setGlobalProxy(ProxyProperties proxyProperties) {
enforceConnectivityInternalPermission();
synchronized (mProxyLock) {
if (proxyProperties == mGlobalProxy) return;
if (proxyProperties != null && proxyProperties.equals(mGlobalProxy)) return;
if (mGlobalProxy != null && mGlobalProxy.equals(proxyProperties)) return;
String host = "";
int port = 0;
String exclList = "";
String pacFileUrl = "";
if (proxyProperties != null && (!TextUtils.isEmpty(proxyProperties.getHost()) ||
!TextUtils.isEmpty(proxyProperties.getPacFileUrl()))) {
if (!proxyProperties.isValid()) {
if (DBG)
log("Invalid proxy properties, ignoring: " + proxyProperties.toString());
return;
}
mGlobalProxy = new ProxyProperties(proxyProperties);
host = mGlobalProxy.getHost();
port = mGlobalProxy.getPort();
exclList = mGlobalProxy.getExclusionList();
if (proxyProperties.getPacFileUrl() != null) {
pacFileUrl = proxyProperties.getPacFileUrl();
}
} else {
mGlobalProxy = null;
}
ContentResolver res = mContext.getContentResolver();
final long token = Binder.clearCallingIdentity();
try {
//保存host和port
Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_HOST, host);
Settings.Global.putInt(res, Settings.Global.GLOBAL_HTTP_PROXY_PORT, port);
Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
exclList);
Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_PAC, pacFileUrl);
} finally {
Binder.restoreCallingIdentity(token);
}
}
if (mGlobalProxy == null) {
proxyProperties = mDefaultProxy;
}
//发送通知
sendProxyBroadcast(proxyProperties);
}
//发送广播Proxy.PROXY_CHANGE_ACTION
private void sendProxyBroadcast(ProxyProperties proxy) {
if (proxy == null) proxy = new ProxyProperties("", 0, "");
if (mPacManager.setCurrentProxyScriptUrl(proxy)) return;
if (DBG) log("sending Proxy Broadcast for " + proxy);
Intent intent = new Intent(Proxy.PROXY_CHANGE_ACTION);
intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING |
Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
intent.putExtra(Proxy.EXTRA_PROXY_INFO, proxy);
final long ident = Binder.clearCallingIdentity();
try {
mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
frameworks/base/core/java/android/app/ContextImpl.java
public void sendStickyBroadcastAsUser(Intent intent, UserHandle user) {
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
intent.prepareToLeaveProcess();
ActivityManagerNative.getDefault().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, false, true, user.getIdentifier());
} catch (RemoteException e) {
}
}
public final int broadcastIntent(IApplicationThread caller,
Intent intent, String resolvedType, IIntentReceiver resultTo,
int resultCode, String resultData, Bundle map,
String requiredPermission, int appOp, boolean serialized, boolean sticky, int userId) {
enforceNotIsolatedCaller("broadcastIntent");
synchronized(this) {
intent = verifyBroadcastLocked(intent);
final ProcessRecord callerApp = getRecordForAppLocked(caller);
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
int res = broadcastIntentLocked(callerApp,
callerApp != null ? callerApp.info.packageName : null,
intent, resolvedType, resultTo,
resultCode, resultData, map, requiredPermission, appOp, serialized, sticky,
callingPid, callingUid, userId);
Binder.restoreCallingIdentity(origId);
return res;
}
}
//接收处理Proxy.PROXY_CHANGE_ACTION
private final int broadcastIntentLocked(ProcessRecord callerApp,
String callerPackage, Intent intent, String resolvedType,
IIntentReceiver resultTo, int resultCode, String resultData,
Bundle map, String requiredPermission, int appOp,
boolean ordered, boolean sticky, int callingPid, int callingUid,
int userId) {
...
if (Proxy.PROXY_CHANGE_ACTION.equals(intent.getAction())) {
ProxyProperties proxy = intent.getParcelableExtra("proxy");
mHandler.sendMessage(mHandler.obtainMessage(UPDATE_HTTP_PROXY_MSG, proxy));
}
...
}
//handler接收UPDATE_HTTP_PROXY_MSG,解析出host,port,调用ApplicationThread的setHttpProxy
case UPDATE_HTTP_PROXY_MSG: {
ProxyProperties proxy = (ProxyProperties)msg.obj;
String host = "";
String port = "";
String exclList = "";
String pacFileUrl = null;
if (proxy != null) {
host = proxy.getHost();
port = Integer.toString(proxy.getPort());
exclList = proxy.getExclusionList();
pacFileUrl = proxy.getPacFileUrl();
}
synchronized (ActivityManagerService.this) {
for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
ProcessRecord r = mLruProcesses.get(i);
if (r.thread != null) {
try {
r.thread.setHttpProxy(host, port, exclList, pacFileUrl);
} catch (RemoteException ex) {
Slog.w(TAG, "Failed to update http proxy for: " +
r.info.processName);
}
}
}
}
} break;
ApplicationThread属于frameworks/base/core/java/android/app/ActivityThread.java的内部类
public void setHttpProxy(String host, String port, String exclList, String pacFileUrl) {
Proxy.setHttpProxySystemProperty(host, port, exclList, pacFileUrl);
}
public static final void setHttpProxySystemProperty(String host, String port, String exclList,
String pacFileUrl) {
if (exclList != null) exclList = exclList.replace(",", "|");
if (false) Log.d(TAG, "setHttpProxySystemProperty :"+host+":"+port+" - "+exclList);
if (host != null) {
System.setProperty("http.proxyHost", host);
System.setProperty("https.proxyHost", host);
} else {
System.clearProperty("http.proxyHost");
System.clearProperty("https.proxyHost");
}
if (port != null) {
System.setProperty("http.proxyPort", port);
System.setProperty("https.proxyPort", port);
} else {
System.clearProperty("http.proxyPort");
System.clearProperty("https.proxyPort");
}
if (exclList != null) {
System.setProperty("http.nonProxyHosts", exclList);
System.setProperty("https.nonProxyHosts", exclList);
} else {
System.clearProperty("http.nonProxyHosts");
System.clearProperty("https.nonProxyHosts");
}
if (!TextUtils.isEmpty(pacFileUrl)) {
ProxySelector.setDefault(new PacProxySelector());
} else {
ProxySelector.setDefault(sDefaultProxySelector);
}
}
IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
if (b != null) {
// In pre-boot mode (doing initial launch to collect password), not
// all system is up. This includes the connectivity service, so don't
// crash if we can't get it.
IConnectivityManager service = IConnectivityManager.Stub.asInterface(b);
try {
ProxyProperties proxyProperties = service.getProxy();
Proxy.setHttpProxySystemProperty(proxyProperties);
} catch (RemoteException e) {}
}
public RouteSelector(Address address, URI uri, ProxySelector proxySelector, ConnectionPool pool,
Dns dns, RouteDatabase routeDatabase) {
this.address = address;
this.uri = uri;
this.proxySelector = proxySelector;
this.pool = pool;
this.dns = dns;
this.routeDatabase = routeDatabase;
this.postponedRoutes = new LinkedList<Route>();
//读取是否设置全局代理
resetNextProxy(uri, address.getProxy());
}
//proxy为null,使用全局或者wifi代理,非应用内代理
/** Resets {@link #nextProxy} to the first option. */
private void resetNextProxy(URI uri, Proxy proxy) {
this.hasNextProxy = true; // This includes NO_PROXY!
if (proxy != null) {
this.userSpecifiedProxy = proxy;
} else {//根据uri获取代理
List<Proxy> proxyList = proxySelector.select(uri);
if (proxyList != null) {
this.proxySelectorProxies = proxyList.iterator();
}
}
}
private static ProxySelector defaultSelector = new ProxySelectorImpl();
//入口
@Override public List<Proxy> select(URI uri) {
return Collections.singletonList(selectOneProxy(uri));
}
//解析url的请求类型,查找设置的java环境变量中的代理host和port
private Proxy selectOneProxy(URI uri) {
if (uri == null) {
throw new IllegalArgumentException("uri == null");
}
String scheme = uri.getScheme();
if (scheme == null) {
throw new IllegalArgumentException("scheme == null");
}
int port = -1;
Proxy proxy = null;
String nonProxyHostsKey = null;
boolean httpProxyOkay = true;
if ("http".equalsIgnoreCase(scheme)) {
port = 80;
nonProxyHostsKey = "http.nonProxyHosts";
proxy = lookupProxy("http.proxyHost", "http.proxyPort", Proxy.Type.HTTP, port);
} else if ("https".equalsIgnoreCase(scheme)) {
port = 443;
nonProxyHostsKey = "https.nonProxyHosts"; // RI doesn't support this
proxy = lookupProxy("https.proxyHost", "https.proxyPort", Proxy.Type.HTTP, port);
} else if ("ftp".equalsIgnoreCase(scheme)) {
port = 80; // not 21 as you might guess
nonProxyHostsKey = "ftp.nonProxyHosts";
proxy = lookupProxy("ftp.proxyHost", "ftp.proxyPort", Proxy.Type.HTTP, port);
} else if ("socket".equalsIgnoreCase(scheme)) {
httpProxyOkay = false;
} else {
return Proxy.NO_PROXY;
}
if (nonProxyHostsKey != null
&& isNonProxyHost(uri.getHost(), System.getProperty(nonProxyHostsKey))) {
return Proxy.NO_PROXY;
}
if (proxy != null) {
return proxy;
}
if (httpProxyOkay) {
proxy = lookupProxy("proxyHost", "proxyPort", Proxy.Type.HTTP, port);
if (proxy != null) {
return proxy;
}
}
proxy = lookupProxy("socksProxyHost", "socksProxyPort", Proxy.Type.SOCKS, 1080);
if (proxy != null) {
return proxy;
}
return Proxy.NO_PROXY;
}
private Proxy lookupProxy(String hostKey, String portKey, Proxy.Type type, int defaultPort) {
String host = System.getProperty(hostKey);
if (host == null || host.isEmpty()) {
return null;
}
int port = getSystemPropertyInt(portKey, defaultPort);
return new Proxy(type, InetSocketAddress.createUnresolved(host, port));
}
//proxySelectorProxies不为null了
private Proxy nextProxy() {
// If the user specifies a proxy, try that and only that.
if (userSpecifiedProxy != null) {
hasNextProxy = false;
return userSpecifiedProxy;
}
// Try each of the ProxySelector choices until one connection succeeds. If none succeed
// then we'll try a direct connection below.
if (proxySelectorProxies != null) {
while (proxySelectorProxies.hasNext()) {
Proxy candidate = proxySelectorProxies.next();
if (candidate.type() != Proxy.Type.DIRECT) {
return candidate;
}
}
}
// Finally try a direct connection.
hasNextProxy = false;
return Proxy.NO_PROXY;
}
//上篇文章dns入口,proxy不为空,类型为http
private void resetNextInetSocketAddress(Proxy proxy) throws UnknownHostException {
socketAddresses = null; // Clear the addresses. Necessary if getAllByName() below throws!
String socketHost;
if (proxy.type() == Proxy.Type.DIRECT) {
socketHost = uri.getHost();
socketPort = getEffectivePort(uri);
} else {
SocketAddress proxyAddress = proxy.address();
if (!(proxyAddress instanceof InetSocketAddress)) {
throw new IllegalArgumentException(
"Proxy.address() is not an " + "InetSocketAddress: " + proxyAddress.getClass());
}
InetSocketAddress proxySocketAddress = (InetSocketAddress) proxyAddress;
//代理服务器的host
socketHost = proxySocketAddress.getHostName();
socketPort = proxySocketAddress.getPort();
}
// Try each address for best behavior in mixed IPv4/IPv6 environments.
socketAddresses = dns.getAllByName(socketHost);
nextSocketAddressIndex = 0;
}
设置WiFi代理流程:
submit->//WifiSettings.java,新增wifi或者修改ip、代理等保存
== save->//WifiManager.java,内部封装Messenger远程调用
==== handleMessage->//WifiService.java,接收远程调用
====== sendMessage->//WifiStateMachine.java,获取WifiConfiguration
======== saveNetwork->//WifiConfigStore.java
========== addOrUpdateNetworkNative-> //新增或者更新wifi
============ writeIpAndProxyConfigurationsOnChange-> //把远程传进来的ip、代理等写入当前进程的WifiConfiguration
========== enableNetwork/saveConfig -> //把配置信息保存到wpa_supplicant,之后触发一些广播
…
handleConnectivityChange->接收处理LINK_CONFIGURATION_CHANGED_ACTION
handleConnect->接收处理NETWORK_STATE_CHANGED_ACTION
==== handleApplyDefaultProxy-> //全局代理的优先级应该比wifi代理高
====== sendProxyBroadcast-> //发送广播Proxy.PROXY_CHANGE_ACTION
======== broadcastIntentLocked->//接收处理Proxy.PROXY_CHANGE_ACTION,ActivityManagerService.java
========== setHttpProxy->//ApplicationThread的setHttpProxy,回到应用进程执行,ActivityThread.java
============ setHttpProxySystemProperty->//Proxy.java,设置java环境变量,存储http、https的代理host、port。
//应用进程启动情况下
handleBindApplication->//ActivityThread.java
== getProxy->//跨进程调用ConnectivityService.java
==== setHttpProxySystemProperty->//Proxy.java
====== setHttpProxySystemProperty->//Proxy.java
设置全局代理流程:Settings.Global.GLOBAL_HTTP_PROXY_HOST/Settings.Global.HTTP_PROXY
SettingsObserver->//ConnectivityService.java,监听Settings.Global.HTTP_PROXY
handleDeprecatedGlobalHttpProxy->//解析出host,port
==setGlobalProxy->//Settings.Global.GLOBAL_HTTP_PROXY_HOST存储host
====sendProxyBroadcast->//发送广播Proxy.PROXY_CHANGE_ACTION
======broadcastIntentLocked->//接收处理Proxy.PROXY_CHANGE_ACTION,ActivityManagerService.java
========setHttpProxy->//ApplicationThread的setHttpProxy,回到应用进程执行,ActivityThread.java
==========setHttpProxySystemProperty->//Proxy.java,设置java环境变量,存储http、https的代理host、port。
//应用进程启动情况下
handleBindApplication->//ActivityThread.java
==getProxy->//跨进程调用ConnectivityService.java
====setHttpProxySystemProperty->//Proxy.java
======setHttpProxySystemProperty->//Proxy.java
代理生效流程如下:
…略过
RouteSelector->//构造函数
==resetNextProxy->//根据uri获取代理
====select->//ProxySelectorImpl.java
======selectOneProxy->//解析url的请求类型,查找设置的java环境变量中的代理host和port
========lookupProxy->//返回proxy
==========nextProxy->//发起网络请求前先检查是否设置代理
============resetNextInetSocketAddress->//获取dns,如果有设置代理,替换host和port为代理服务器。
代码实现设置WiFi代理
所以先断开连接再连接,触发广播,使代理立即生效。
private WifiConfiguration getCurrentWifiConfiguration(WifiManager manager) {
if (manager == null || !manager.isWifiEnabled())
return null;
List<WifiConfiguration> configurationList = manager.getConfiguredNetworks();
WifiConfiguration configuration = null;
int networkId = manager.getConnectionInfo().getNetworkId();
for (int i = 0; i < configurationList.size(); ++i) {
WifiConfiguration wifiConfiguration = configurationList.get(i);
if (wifiConfiguration.networkId == networkId)
configuration = wifiConfiguration;
}
return configuration;
}
//打印下设置过的代理
private boolean getWiFiProxySettings() {
// 获得 WifiConfiguration
WifiManager manager = (WifiManager) this.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
WifiConfiguration config = getCurrentWifiConfiguration(manager);
if (null == config)
return false;
try {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {//26
ProxyInfo httpProxy = config.getHttpProxy();
Log.e("zhuo", "httpProxy="+httpProxy);
}
// 从 WifiConfiguration 中获得 linkProperties
Object linkProperties = getField(config, "linkProperties");
if (null == linkProperties)
return false;
// 获得 getHttpProxy 方法
Class<?> proxyPropertiesClass = Class.forName("android.net.ProxyProperties");
Class<?> lpClass = Class.forName("android.net.LinkProperties");
Method getHttpProxy = lpClass.getDeclaredMethod("getHttpProxy");
getHttpProxy.setAccessible(true);
Object proxyProperties = getHttpProxy.invoke(linkProperties);
Log.e("zhuo", "proxyProperties="+proxyProperties);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
//传入代理host和port
private boolean setWiFiProxySettings(String ip, int port) {
// 获得 WifiConfiguration
WifiManager manager = (WifiManager) this.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
WifiConfiguration config = getCurrentWifiConfiguration(manager);
if (null == config)
return false;
try {
// 从 WifiConfiguration 中获得 linkProperties
Object linkProperties = getField(config, "linkProperties");
if (null == linkProperties)
return false;
// 获得 setHttpProxy 方法
Class<?> ProxyProperties = Class.forName("android.net.ProxyProperties");
Class<?> LinkProperties = Class.forName("android.net.LinkProperties");
Method setHttpProxy = LinkProperties.getDeclaredMethod("setHttpProxy", ProxyProperties);
setHttpProxy.setAccessible(true);
// 获得 ProxyProperties 构造方法
Constructor proxyPropertiesCtor = ProxyProperties.getConstructor(String.class, int.class, String.class);
// 创建 ProxyProperties 的对象
Object proxySettings = proxyPropertiesCtor.newInstance(ip, port, null);
// 反射调用 linkProperties 的 setHttpProxy 方法, 参数为 ProxyProperties
setHttpProxy.invoke(linkProperties, proxySettings);
setProxySettings("STATIC", config);
// 保存设置
manager.updateNetwork(config);
manager.disconnect();
manager.reconnect();//需先断开再连接
Log.e("zhuo", "保存Proxy设置成功");
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
通过以上代码可以设置WiFi代理,可以把其他应用的HTTP(S)代理到设置的代理服务器。
补充
HttpURLConnectionImpl.java:
private boolean execute(boolean readResponse) throws IOException {
try {
httpEngine.sendRequest();
if (readResponse) {
httpEngine.readResponse();
}
return true;
} catch (IOException e) {
//捕获异常
if (handleFailure(e)) {
return false;
} else {
throw e;
}
}
}
//routeSelector.connectFailed,把异常传递给RouteSelector
private boolean handleFailure(IOException e) throws IOException {
RouteSelector routeSelector = httpEngine.routeSelector;
if (routeSelector != null && httpEngine.connection != null) {
routeSelector.connectFailed(httpEngine.connection, e);
}
OutputStream requestBody = httpEngine.getRequestBody();
boolean canRetryRequestBody = requestBody == null
|| requestBody instanceof RetryableOutputStream;
if (routeSelector == null && httpEngine.connection == null // No connection.
|| routeSelector != null && !routeSelector.hasNext() // No more routes to attempt.
|| !isRecoverable(e)
|| !canRetryRequestBody) {
httpEngineFailure = e;
return false;
}
httpEngine.release(true);
RetryableOutputStream retryableOutputStream = (RetryableOutputStream) requestBody;
httpEngine = newHttpEngine(method, rawRequestHeaders, null, retryableOutputStream);
httpEngine.routeSelector = routeSelector; // Keep the same routeSelector.
return true;
}
public void connectFailed(Connection connection, IOException failure) {
Route failedRoute = connection.getRoute();
if (failedRoute.getProxy().type() != Proxy.Type.DIRECT && proxySelector != null) {
// Tell the proxy selector when we fail to connect on a fresh connection.
proxySelector.connectFailed(uri, failedRoute.getProxy().address(), failure);
}
routeDatabase.failed(failedRoute, failure);
}
//再次进行网络请求,执行到routeDatabase.shouldPostpone,因为不能连通的代理已经在路由表(黑名单)中,所以继续调用自身,跳过了代理
public Connection next(String method) throws IOException {
// Always prefer pooled connections over new connections.
for (Connection pooled; (pooled = pool.get(address)) != null; ) {
if (method.equals("GET") || pooled.isReadable()) return pooled;
pooled.close();
}
// Compute the next route to attempt.
if (!hasNextTlsMode()) {
if (!hasNextInetSocketAddress()) {
if (!hasNextProxy()) {
if (!hasNextPostponed()) {
throw new NoSuchElementException();
}
return new Connection(nextPostponed());
}
lastProxy = nextProxy();
resetNextInetSocketAddress(lastProxy);
}
lastInetSocketAddress = nextInetSocketAddress();
resetNextTlsMode();
}
boolean modernTls = nextTlsMode() == TLS_MODE_MODERN;
Route route = new Route(address, lastProxy, lastInetSocketAddress, modernTls);
if (routeDatabase.shouldPostpone(route)) {
postponedRoutes.add(route);
// We will only recurse in order to skip previously failed routes. They will be
// tried last.
return next(method);
}
return new Connection(route);
}
看雪ID:卓桐
https://bbs.pediy.com/user-670707.htm
推荐文章++++